package com.blockchain.coupon.service.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import com.blockchain.coupon.po.ConsumerCoupon;
import com.blockchain.coupon.po.ConsumerCustom;
import com.blockchain.coupon.rpc.Web3;
import com.blockchain.coupon.service.ConsumerService;
import net.sf.json.JSONObject;

import org.springframework.beans.factory.annotation.Autowired;

import com.blockchain.coupon.mapper.ConsumerMapper;
import com.blockchain.coupon.mapper.CouponMapper;
import com.blockchain.coupon.po.CouponApplicationCustom;
import com.blockchain.coupon.po.CouponCustom;
import com.blockchain.coupon.po.CouponPayApplicationCustom;
import com.blockchain.coupon.sha3.Sha3;
import com.blockchain.coupon.util.DateUtil;
import com.blockchain.coupon.util.Encryption;
import com.blockchain.coupon.util.ReadAccount;

public class ConsumerServiceImpl implements ConsumerService {
	
	@Autowired
	private ConsumerMapper consumerMapper;
	
	@Autowired
	private CouponMapper couponMapper;

//	注册消费者
	public String consumerRegister(ConsumerCustom consumerCustom) throws Exception {
		// TODO Auto-generated method stub
		try {
			ConsumerCustom cc=consumerMapper.queryConsumerInfoByAccount(consumerCustom.getAccount());
			if(cc!=null){
				return "0";
			}
			consumerCustom.setId(UUID.randomUUID().toString());
			consumerCustom.setSalt(Encryption.createSalt());
			consumerCustom.setPassword(Sha3.sha3(consumerCustom.getPassword()+consumerCustom.getSalt()));

			String consumerAccount=ReadAccount.getAccount("consumerAccount");
			consumerCustom.setPublicKey(consumerAccount);
			
//		创建消费者合约
			String functionName = "eth_compileSolidity";
			Boolean flag = null;
			String object = null;
			String[] content={"contract Main{ address owner; address[] merchants; address banker; function Main(){ address operatorAddr = 0x123; address checkerAddr = 0x456; owner = msg.sender; banker = new Bank(operatorAddr,checkerAddr,msg.sender); } modifier onlyOwner(){ if(msg.sender!=owner) throw; _ } function createMerchant(address merchant) onlyOwner{ merchants.push(new Merchant(owner,merchant)); } function approve( bytes signature, address _merchant, uint value, bool isAdd ) onlyOwner{ Bank bank = Bank(banker); bank.approve(signature,_merchant,value,isAdd,msg.sender); } function getBankAddress() constant returns(address){ return banker; } function getMerchants() constant returns(address[]){ return merchants; } function getMerchantLatest() constant returns(address){ return merchants[merchants.length-1]; } } contract Bank{ address operatorAddr; address checkerAddr; address owner; function Bank(address opKey,address ckKey,address sender){ operatorAddr = opKey; checkerAddr = ckKey; owner = sender; } function approve( bytes signature, address _merchant, uint value, bool isAdd, address sender ) onlyOwner(sender) { if(check(signature)){ Merchant merchant = Merchant(_merchant); merchant.updateBalance(value,isAdd); } } function setPermissions(bool _issuePermission,bool _chargePermission,address _merchant,address sender) onlyOwner(sender){ Merchant merchant = Merchant(_merchant); merchant.setPermissions(_issuePermission,_chargePermission,owner); } function check(bytes signature) returns(bool ){ bool result = true; return result; } modifier onlyOwner(address sender){ if(sender!=owner) throw; _ } } contract Merchant { address banker; address owner; uint balance; bool issuePermission; bool chargePermission; address[] issuedCoupon; address[] notIssuedCoupon; address[] settlementCoupon; address[] latestIssue; address[] latestNotIssue; function Merchant(address bank,address sender ){ banker = bank; owner = sender; } modifier onlyOwner(){ if(msg.sender!=owner) throw; _ } modifier onlyBanker(address bankerAccount) { if(bankerAccount!=banker) throw; _ } function issue(uint value,bytes validStart,bytes validEnd) onlyOwner { notIssuedCoupon.push(new Coupon(value,validStart,validEnd,owner)); balance = balance - value; } function issueMany(uint value,bytes validStart,bytes validEnd,uint quantity) onlyOwner { if(issuePermission!=true) throw; for(uint i=0;i<quantity;i++){ issue(value,validStart,validEnd); } } function queryCouponQuantities() onlyOwner constant returns(uint,uint,uint){ } function getNotIssuedCoupon() constant returns(address[]){ return notIssuedCoupon; } function getIssuedCoupon() constant returns(address[]){ return issuedCoupon; } function getSettlementCoupon() constant returns(address[]){ return settlementCoupon; } function getNotIssuedQuantity() constant returns(uint){ return notIssuedCoupon.length; } function getIssuedCouponQuantity() constant returns(uint){ return issuedCoupon.length; } function getSettlementCouponQuantity() constant returns(uint){ return settlementCoupon.length; } function getLatestIssuedCouponByQuantity(uint quantity) constant returns(address[]){ delete latestIssue; for(uint i=issuedCoupon.length-quantity;i<issuedCoupon.length;i++){ latestIssue.push(issuedCoupon[i]); } return latestIssue; } function getLatestNotIssuedCouponByQuantity(uint quantity) constant returns(address[]){ delete latestNotIssue; for(uint i=notIssuedCoupon.length-quantity;i<notIssuedCoupon.length;i++){ latestNotIssue.push(notIssuedCoupon[i]); } return latestNotIssue; } function getAllCouponsValue() onlyOwner constant returns(uint,uint,uint,uint){ } function terminateIssue() onlyOwner{ } function fundSettlement() { } function grant( uint value, uint consumptionValue, address _consumer, bytes date ) onlyOwner { uint currentQuantity = notIssuedCoupon.length; if(currentQuantity<0) throw; Coupon c = Coupon(notIssuedCoupon[currentQuantity-1]); uint couponValue = c.getValue(); uint quantity = value/couponValue; if(currentQuantity<quantity) throw; for(uint i=0;i<quantity;i++){ address couponAddress = notIssuedCoupon[currentQuantity-1]; Coupon coupon = Coupon(couponAddress); coupon.consumeRecording(date,_consumer,consumptionValue); coupon.setState(Coupon.CouponState.Granted); issuedCoupon.push(couponAddress); currentQuantity = currentQuantity - 1; Consumer consumer = Consumer(_consumer); consumer.addCoupon(couponAddress); } notIssuedCoupon.length = notIssuedCoupon.length - quantity; } function setPermissions( bool _issuePermission, bool _chargePermission, address bankAccount ) onlyBanker(bankAccount) { issuePermission = _issuePermission; chargePermission = _chargePermission; } function setAccount() { } function getPermission() constant returns(bool){ return issuePermission; } function payConfirm( address _consumer, address[] couponAddress ) { if(!chargePermission) throw; Consumer consumer = Consumer(_consumer); consumer.payCoupon(couponAddress); for(uint i=0;i<couponAddress.length;i++){ settlementCoupon.push(couponAddress[i]); Coupon c = Coupon(couponAddress[i]); balance = balance + c.getValue(); } } function updateBalance(uint value,bool isAdd){ if(isAdd){ balance = balance + value; }else{ balance = balance - value; } } function getBalance() constant returns(uint){ return balance; } } contract Coupon { address publisher; address owner; uint value; bytes validStart; bytes validEnd; struct Consumption { bytes date; address consumer; uint amount; } Consumption consumption; enum CouponState {Issuing,Granted,Used,Withdrawn} CouponState state; function Coupon( uint _value, bytes _validStart, bytes _validEnd, address _publisher ) { value = _value; validStart = _validStart; validEnd = _validEnd; publisher = _publisher; owner = _publisher; state = CouponState.Issuing; } function consumeRecording( bytes date, address consumer, uint amount ) { consumption = Consumption(date,consumer,amount); } function transfer( address receiver ) { } function payApply( address merchant ) { } function getValue() constant returns(uint){ return value; } function setState(CouponState st){ state = st; } function getState() constant returns(CouponState){ return state; } function getRecording() constant returns(bytes,address,uint){ return (consumption.date,consumption.consumer,consumption.amount); } } contract Consumer { address banker; address owner; bool state; address[] coupons; function Consumer(){ owner = msg.sender; } function getCoupon( Coupon coupon ){ } function setState(bool _state){ } function queryCoupons(){ } function addCoupon(address coupon){ coupons.push(coupon); } function payCoupon(address[] coups) { for(uint i=0;i<coups.length;i++){ Coupon c = Coupon(coups[i]); c.setState(Coupon.CouponState.Used); for(uint j=0;j<coupons.length;j++){ if(coupons[j]==coups[i]){ coupons[j] = 0; } } } } function getCoupons() constant returns(address[]){ return coupons; } }"};
			String result= Web3.universalCall(functionName, object, content, flag);

			JSONObject js=JSONObject.fromObject(result);
			JSONObject multi=(JSONObject) js.get("Consumer");
			String code=multi.getString("code");
			
			String functionName1 = "eth_estimateGas";
			Boolean flag1 = null;
			String object1 = "{\"from\": \""+consumerAccount+"\",  \"data\": \""+code+"\"}";
			String[] content1 = null;
			String gas=Web3.universalCall(functionName1, object1, content1, flag1);
			
			String functionName2 = "eth_sendTransaction";
			Boolean flag2 = null;
			String object2 = "{\"from\": \""+consumerAccount+"\", \"gas\": \""+gas+"\", \"data\": \""+code+"\"}";
			String[] content2 = null;
			String txHash=Web3.universalCall(functionName2, object2, content2, flag2);
			
			String functionName3 = "eth_getTransactionReceipt";
			String[] content3 = {txHash};
			String finish="null";
			while(finish.equals("null")){
				finish = Web3.universalCall(functionName3, null, content3, null);
			}
			JSONObject tsxInfo=JSONObject.fromObject(finish);
			String contractAddress=tsxInfo.getString("contractAddress");
			System.out.println("===========");
			System.out.println(contractAddress);
			System.out.println("===========");
			consumerCustom.setContractAddress(contractAddress);
			consumerMapper.insertConsumer(consumerCustom);
			
			return "1";
		} catch (Exception e) {
			// TODO Auto-generated catch block
			return "0";
		}
	}

//	登录
	public Map<String, String> consumerLogin(String account,String password) throws Exception {
		ConsumerCustom mc=consumerMapper.queryConsumerInfoByAccount(account);
		Map<String, String> m=new HashMap<String, String>();
		if(mc!=null){
			String encryptionPasswd=Sha3.sha3(password+mc.getSalt());
			if(encryptionPasswd.equals(mc.getPassword())){
				try {
					m.put("resultCode", "1");
					m.put("id", mc.getId());
					String timeStamp=DateUtil.getCurrentTime();
					String token=Sha3.sha3(account+password+timeStamp);
					m.put("token", token);
					mc.setToken(token);
					consumerMapper.updateToken(mc);
					return m;
				} catch (Exception e) {
					// 如果token指令更新失败
					m.put("resultCode", "-1");
					return m;
				}
			}else{
				m.put("resultCode", "0");
				return m;
			}
		}else{
			m.put("resultCode", "0");
			return m;
		}
	}

	public List<ConsumerCoupon> consumerQueryUnusedCoupons(String consumerId) {
		return consumerMapper.consumerQueryUnusedCoupons(consumerId);
	}
     
// 插入优惠券申请
	public String insertCouponApplication(CouponApplicationCustom couponApplicationCustom) throws Exception {
		// TODO Auto-generated method stub
		try {
			couponApplicationCustom.setId(UUID.randomUUID().toString());
			couponApplicationCustom.setConsumptionTime(DateUtil.getCurrentTime());
			couponMapper.insertCouponApplication(couponApplicationCustom);
			return "1";
		} catch (Exception e) {
			// TODO Auto-generated catch block
			return "0";
		}
	}
	
//	插入优惠券支付申请
	public String insertCouponPayApp(String merchantId, String consumerId, String couponIds) throws Exception {
		// TODO Auto-generated method stub
		try {
			String[] strs=couponIds.split(",");
			String applicationCode=UUID.randomUUID().toString();
			CouponCustom cc=new CouponCustom();
			for(String couponId:strs){
				CouponPayApplicationCustom cpac=new CouponPayApplicationCustom();
				cpac.setId(UUID.randomUUID().toString());
				cpac.setMerchantId(merchantId);
				cpac.setConsumerId(consumerId);
				cpac.setCouponId(couponId);
				cpac.setApplicationTime(DateUtil.getCurrentTime());
				cpac.setApplicationCode(applicationCode);
				couponMapper.insertCouponPayApp(cpac);
				couponMapper.updateCouponInUse(couponId);
			}
			return "1";
		} catch (Exception e) {
			// TODO Auto-generated catch block
			return "0";
		}
	}
	
}
